#ifndef TIMER_H
#define TIMER_H

#include "EventLoop.hpp"
#include <time.h>
#include <chrono>
#include <set>
#include <sys/timerfd.h>


struct TimerNode {
    time_t expire;
    uint64_t id;
    using CallBack = std::shared_ptr<std::function<void()>>;
    CallBack func;
    int cycle;
    TimerNode(time_t expire, uint64_t id, const std::function<void ()>& f, int cycle=0) {
        this->expire = expire;
        this ->id = id;
        this->func = std::make_shared<std::function<void()>>(f);
        this->cycle = cycle;
    }
    TimerNode(time_t expire, uint64_t id, CallBack f, int cycle=0) {
        this->expire = expire;
        this ->id = id;
        this->func = f;
        this->cycle = cycle;
    }

};


bool operator<(const TimerNode& l, const TimerNode& r);


class Timer {
public:
    Timer(EventLoop* loop);

    inline static time_t getTick() {
        return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
    }

    void addTimer(int time, const std::function<void()>& func, bool cycle) {
        time_t expire = getTick()+time;
        if (!cycle) timeouts_.emplace(expire, genId(), func, 0);
        else {
            timeouts_.emplace(expire, genId(), func, time);
        }
        // 接下来需要比较一下timerfd的时间和新加进来的时间哪个更近。
        struct itimerspec current_value;
        int ret = timerfd_gettime(timerfd_, &current_value);
        if (current_value.it_value.tv_sec * 1000 + current_value.it_value.tv_nsec / 1000000 > time) {
            struct itimerspec new_value = {};
            new_value.it_value.tv_sec  = time / 1000; 
            new_value.it_value.tv_nsec = time % 1000 * 1000000;
            
            new_value.it_interval.tv_sec  = 0; // one shot
            new_value.it_interval.tv_nsec = 0;
            if (timerfd_settime(timerfd_, 0, &new_value, NULL) == -1)
            {
                perror("timerfd_settime");
            }

        }

        
    }

    void consumeTimeEvent();


private:
    inline static uint64_t genId() {
        return gid++;
    }
    static uint64_t gid;
    EventLoop* loop_;

    std::set<TimerNode> timeouts_;
    int timerfd_;

};



#endif